package com.my.netty.nio.bytebuffer;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

@Slf4j
public class ByteBufferTest2 {

    private final String USER_DIR = System.getProperty("user.dir");

    /**
     * ByteBuffer 分散读
     */
    @Test
    public void testFsd() {
        try (RandomAccessFile randomAccessFile = new RandomAccessFile(USER_DIR + "/files/word1.txt", "r")) {
            FileChannel fileChannel = randomAccessFile.getChannel();
            ByteBuffer buf1 = ByteBuffer.allocate(5);
            ByteBuffer buf2 = ByteBuffer.allocate(5);
            //传入ByteBuffer数组，将文件内容分散读到2个ByteBuffer
            fileChannel.read(new ByteBuffer[]{buf1, buf2});
            buf1.flip();
            buf2.flip();
            log.info("读取文件完成 buf1:{} buf2:{}", Charset.defaultCharset().decode(buf1), Charset.defaultCharset().decode(buf2));
        } catch (Exception e) {
            log.error("读取文件失败", e);
        }

    }

    /**
     * ByteBuffer 集中写
     */
    @Test
    public void testJzx() {
        try (RandomAccessFile randomAccessFile = new RandomAccessFile(USER_DIR + "/files/word2.txt", "rw")) {
            FileChannel fileChannel = randomAccessFile.getChannel();
            //以下两个ByteBuffer自动是读模式
            ByteBuffer buf1 = Charset.defaultCharset().encode("你好");
            ByteBuffer buf2 = Charset.defaultCharset().encode("啊");
            //传入ByteBuffer数组，将2个ByteBuffer集中写入到一个文件中
            long len = fileChannel.write(new ByteBuffer[]{buf1, buf2});
            log.info("写文件完成，字节数:{}", len);
        } catch (Exception e) {
            log.error("写文件失败", e);
        }

    }

    /**
     * 粘包与半包
     * 客户端向服务端发送了2条消息（UTF-8编码）：
     * 1.你好\n
     * 2.我是张三\n
     * <p>
     * 但是服务端收到了两个ByteBuffer内容分别是
     * 1. ByteBuffer(你好\n我)
     * 2. ByteBuffer(是张三\n)
     * <p>
     * 服务端如何将两条消息按照换行分隔还原出来？
     */
    @Test
    public void testZbBb() {
        //模拟收到的消息
        ByteBuffer buffer = ByteBuffer.allocate(32);
        buffer.put("你好\n我是张三\n今".getBytes(StandardCharsets.UTF_8));
        split(buffer);

        buffer.put("天天气不错\n".getBytes(StandardCharsets.UTF_8));
        split(buffer);
    }

    private void split(ByteBuffer buffer) {
        //切为读模式
        buffer.flip();

        for (int i = 0; i < buffer.limit(); i++) {
            byte b = buffer.get(i);
            if (b == '\n') {
                //存储一条完整消息的ByteBuffer
                int len = i - buffer.position() + 1;
                ByteBuffer msgBuf = ByteBuffer.allocate(len);
                for (int j = 0; j < len; j++) {
                    msgBuf.put(buffer.get());
                }
                //打印消息内容
                msgBuf.flip();
                log.warn("拆分出1条消息: {}", StandardCharsets.UTF_8.decode(msgBuf));
            }
        }

        //切回写模式，并删除已处理的字节，供下次接收数据
        buffer.compact();
    }
}
